/*
 * This file is part of Nest.
 * Nest - http://transmote.com/nest/ is a
 * derivative of Processing - http://processing.org/ 
 * Copyright (C) 2011, Eric Socolofsky
 * 
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 * 
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package com.transmote.nest.events;

/**
 * <p>
 * Event instances represent generic events dispatched by the Nest framework;
 * Event can be subclassed for custom event development.
 * </p>
 * 
 * @author		Eric Socolofsky
 * @see			EventDispatcher
 */
public class Event {
	private static final boolean DEFAULT_BUBBLES = false;
	
	/**
	 * Event type dispatched when {@link EventDispatcher#dispose()} is called.
	 */
	public static final int DISPATCHER_DISPOSE = 1;
	
	/**
	 * Event type dispatched when a NestSprite is added as a child to another NestSprite,
	 * via {@link com.transmote.nest.NestSprite#addChild(com.transmote.nest.NestSprite)}.
	 */
	public static final int ADDED = 2;
	
	/**
	 * Event type dispatched by a NestSprite and each of its descendants
	 * when it is added to the display list and becomes visible on-screen.
	 */
	public static final int ADDED_TO_STAGE = 3;
	
	/**
	 * Event type dispatched when a NestSprite is removed from its parent,
	 * via {@link com.transmote.nest.NestSprite#removeChild(com.transmote.nest.NestSprite)}.
	 */
	public static final int REMOVED = 4;
	
	/**
	 * Event type dispatched when a caught error is handled within
	 * the Nest framework.
	 * NOTE: not currently used.
	 */
	public static final int ERROR = 5;
	
	/**
	 * Event type dispatched when a NestSprite is initialized,
	 * NOTE: not currently used.
	 */
	public static final int INIT = 6;
	
	/**
	 * Enumerated display list event phase.
	 */
	public static enum PHASE {
		/**
		 * The Event instance is moving back up the display list from the event target.
		 */
		BUBBLING,
		
		/**
		 * The Event instance is at the event target.
		 */
		AT_TARGET,
		
		/**
		 * The Event instance is down through the display list toward the event target.
		 */
		CAPTURE,
		
		/**
		 * The Event instance is not traversing the display list.
		 */
		NOT_ON_DISPLAY_LIST;
	}
	
	
	Object target = null;
	EventDispatcher currentTarget = null;
	PHASE phase = PHASE.NOT_ON_DISPLAY_LIST;
	
	protected processing.event.Event pEvent = null;
	private int type = -1;
	private boolean bubbles = DEFAULT_BUBBLES;
	private boolean propagationStopped = false;
	
	/**
	 * A generic Nest event instance.
	 * @param	type		The event type.
	 */
	public Event (int type) {
		this(type, false);
	}
	
	/**
	 * A generic Nest event instance.
	 * @param	type		The event type.
	 * @param	bubbles		Whether or not the event will bubble up the display list.
	 */
	public Event (int type, boolean bubbles) {
		this.type = type;
		this.bubbles = bubbles;
	}
	
	/**
	 * The event type.
	 * Handlers should switch on this type
	 * to respond accordingly to the event.
	 */
	public int type () {
		return type;
	}
	
	/**
	 * Specifies whether or not the event will bubble up the display list.
	 * Defaults to {@value DEFAULT_BUBBLES}.
	 */
	public boolean bubbles () {
		return bubbles;
	}
	
	/**
	 * Enumerated display list event phase.
	 * As an Event instance travels through the Nest display list,
	 * its <tt>phase</tt> changes.  If the Event instance is not on the display list,
	 * <tt>phase</tt> is set to {@link PHASE}.NOT_ON_DISPLAY_LIST.
	 */
	public PHASE phase () {
		return phase;
	}
	
	/**
	 * If dispatched by an {@link EventDispatcher}, the EventDispatcher instance
	 * that dispatched this Event instance.
	 * Otherwise, the Object that dispatched this Event instance.
	 */
	public Object target () {
		return target;
	}
	
	/**
	 * The {@link EventDispatcher} currently processing this Event Instance.
	 */
	public EventDispatcher currentTarget () {
		return currentTarget;
	}
	
	/**
	 * The Processing Event instance generated by Processing,
	 * if applicable (if this Event instance was generated
	 * in response to a mouse or keyboard action).
	 */
	public processing.event.Event processingEvent () {
		return pEvent;
	}
	
	/**
	 * Stop an Event instance traveling through the display list.
	 * Note: Unlike AS3, Nest does not offer a <tt>stopImmediatePropagation()</tt>
	 * 		 method, as each node in the display list (e.g. each NestSprite instance)
	 * 		 can only have one event handler.
	 */
	public void stopPropagation () {
		propagationStopped = true;
	}
	
	/**
	 * Returns <tt>true</tt> if {@link #stopPropagation()} has been called.
	 * else, returns <tt>false</tt>.
	 */
	public boolean isPropagationStopped () {
		return propagationStopped;
	}
	
	@Override
	public String toString () {
		return ("Event::"+ type);
	}
}